/**
 * 自定义数据模型操作
 * @author AndyPan
 * @createdate 2019年1月2日16:19:14
 * @version 1.0.2
 * @remark 所有对组件数据的操作，均继承至CustomModelComponent
 */

import { Component, OnInit, ViewChild, Input, ElementRef, Output, EventEmitter } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { NzModalService, NzMessageService } from 'ng-zorro-antd';
import { OAuthService } from 'angular-oauth2-oidc';

import { FILEURL, LOGININFO } from '../../config';
import { Utils, Lang, Status } from '../../common/helper/util-helper';

import { ZzjFileUploader } from '@zzj/nag-file-uploader';

declare var CryptoJS: any;
@Component({
  selector: 'components-file-upload',
  templateUrl: './file-upload.component.html',
  styleUrls: ['./file-upload.component.scss']
})
export class FileUploadComponent implements OnInit {
  @ViewChild('fileUploader', { static: false }) private fileUploader: ZzjFileUploader;

  // 自定义表单数据
  /**
   * 格式模型：Array[JSON{}]
   * [
   *    {
   *      value: '默认值', text: '文字', key: 'key值，唯一标识，非必填，会自动生成', require: '是否必填，true|false', placeholder: '自定义placeholder文本',
   *      defaultTip: '在验证错误时是否使用默认的提示，true|false', verifyType: '验证类型字符串，多个时以","隔开，也可以使用verifyTypeAry属性传入数组',
   *      verifyTypeAry: '验证类型集合，单个时也可使用verifyType，两者只有一个有效，两者同时传入时，verifyTypeAry优先级高于verifyType',
   *      type: '表单元素类型，默认问input(即文本框)，主要包括(input、password、select、textarea、checkbox-group、radiobox-group、select-group...)'
   *      options: '当type为select时，需要传入下拉选项集合，即：[{value: '值', text: '文本'}, ...]',
   *      customVerify: '自定义验证，可以是正则表达式，也可以是函数，
   *                    如果是函数，会将当前只作为参数提供给函数使用，返回格式为(如果不使用默认提示，至少需要返回状态status)：{status: '验证结果(true/false)'， message: '错误提示消息'})
   *                    如果是正则，可以提供errorMsg自定义错误提示消息，也可不提供，默认为[***(该项的text属性)格式不正确]'
   *      requireIconType: 'static, 让必填红点跟随文本框后面，去除定位'
   *    }
   * ]
   */
  @Input('formData') public modelData: any = [];
  // 自定义Class
  @Input('className') public className: string;
  // 表单验证默认提示
  @Input('defaultTip') public defaultTip: any = true;
  // 禁用表单元素(在提交表单时触发元素禁用效果，提交完成后解除禁用)
  @Input('disabledForm') public disabledForm: boolean;
  // 每一行的上下间距(默认为15px，min：为5px)
  @Input('rowSpace') public rowSpace: string;
  // 文字颜色主题(默认为黑色文字，如果容器背景为黑色，则可设置主题为白色：white)，也可通过自定义Class自行设置字体颜色或其他样式
  @Input('fontColorTheme') public fontColorTheme: string;
  // 是否渲染form元素，默认是渲染的，当custom-form组件的form样式无法满足你的需求时，可以自己布局表单样式，然后将数据与组件共同使用但在组件中不渲染表单，只做数据验证，可以设置该属性为false
  // 注意：这样使用后，操作数据不能更新原视图，需要通过组件获取组件的数据模型去替换原数据模型
  @Input("isRenderForm") public isRenderForm: boolean;
  // 文件上传host
  @Input('fileHost') public fileHost: string = FILEURL;
  // onEntryCallBack
  @Output() public onEntryCallBack = new EventEmitter<any>();
  // 下拉改变事件
  @Output() public onSelectChange = new EventEmitter<any>();
  // 上传文件选择事件
  @Output() public onUploadFileChange = new EventEmitter<any>();
  // 上传开始事件
  @Output() public onUploadFileStart = new EventEmitter<any>();
  // 上传成功事件
  @Output() public onUploadFileSuccess = new EventEmitter<any>();
  // 上传中的文件删除事件
  @Output() public onUploadFileRemove = new EventEmitter<any>();
  // 上传失败事件
  @Output() public onUploadFileFail = new EventEmitter<any>();

  public status = {
    // 是否做文件上传服务认证（当有文件上传功能的Form元素时，会自动做服务认证）
    isFetchFlow: true,
    // 文件名是否显示
    fileNameStatus: false,
    // upload image
    uploadImageData: null,
    // 上传的文件流保存对象
    flowFiles: [],
    // 保存新增属性，用于还原属性
    addNewAttribute: {},
    // 保存修改type为text的数据，用于还原
    textAttribute: {},
    // 保存新增项，用于还原数据
    newItem: {},
    // 保存删除项，用于还原
    deleteItem: {},
    // 保存临时FormData对象
    tempFormData: {},
    // 文件类型
    limitFileType: {
      image: {
        'image/png': true, 'image/jpeg': true, 'image/jpg': true, 'image/gif': true, 'image/bmp': true
      },
      doc: {
        'application/vnd.ms-works': true, 'application/msword': true
      },
      docx: {
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document': true
      },
      xls: {
        'application/vnd.ms-excel': true
      },
      xlsx: {
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': true
      },
      pdf: {
        'application/pdf': true
      },
      txt: {
        'text/plain': true
      },
      mp4: {
        'video/mp4': true
      },
      ppt: {
        'application/vnd.ms-powerpoint': true
      },
      pptx: {
        'application/vnd.openxmlformats-officedocument.presentationml.presentation': true
      },
      zip: {
        'application/x-zip-compressed': true
      }
    }
  };

  public constructor(
    private message: NzMessageService,
    private oauthService: OAuthService,
    public elemRef: ElementRef
  ) {
  }

  /**
   * 第一次初始化
   */
  public ngOnInit() {
    this.install();
  }

  /**
   * 当数据绑定输入属性的值发生变化时调用
   */
  private ngOnChanges() {
    this.install();
  }

  /**
   * 初始装载
   */
  private install() {
    // this.status.isFetchFlow = true;
    this.fetchFlow();
    console.info(this.modelData)
  }

  /**
   * 文件上传选择事件
   * @param event 事件对象
   * @param data 返回的数据
   */
  public uploadFileChange(event: any, data?: any) {
    this.status.fileNameStatus = true;
    let thisData = data || {};
    let e = event || window.event;
    let target = e.target || e.srcElement;
    // 直接跳出 防止第二次打开文件夹不选择文件时报错
    if (!target.files[0]) {
      return;
    }
    console.log('文件后缀', target.files[0].name.split(".")[1])

    let file = target.files[0];
    // 检查文件类型和大小
    let checkState = this.checkFilesTypeAndSize(file, thisData);
    if (checkState == false) {
      return;
    }
    target.result = null;
    this.status.uploadImageData = thisData;
    thisData.value = file.name;
    thisData.file = file;

    // 添加文件到上传组件
    this.fileUploader.add(file);

    if (this.onUploadFileChange) {
      this.onUploadFileChange.emit([file, thisData]);
    }
  }

  /**
   * 检查文件类型和大小
   * @param file <any> 文件对象
   */
  public checkFilesTypeAndSize(file: any, data: any) {
    if (data) {
      let resultState;
      // 限制的文件类型
      let fileLimit = data.limitFileType || '';
      // 限制的文件大小，单位为兆'M'
      let fileSize = data.limitFileSize;
      let typeStr = file.name.split(".")[1];
      fileLimit = fileLimit.split('|');
      let limitFileType = this.status.limitFileType;
      let num = 1024;
      let size = parseFloat(((file.size / num) / num) + '').toFixed(2);
      let type = file.type;
      let i = 0;
      let len = fileLimit.length;
      let limitItem;
      let limitType;
      // 检测文件类型
      console.log('文件对象', file)
      console.log('文件类型', type)
      for (; i < len; i++) {
        limitItem = fileLimit[i];
        limitType = limitFileType[limitItem];
        if (limitType) {
          // console.log('获取已匹配的文件类型' , limitType)
          if (!limitType[type]) {
            resultState = false;
          } else {
            resultState = true;
            return;
          }
        }
      }
      if (!resultState) {
        this.message.warning('不支持的文件类型');
      }
      console.log(resultState)
      if (resultState != false) {
        // 检测文件大小
        if (fileSize) {
          if (size > fileSize) {
            // this.message.warning('上传文件大小超过指定允许上传文件大小最大值('+fileSize+' M)');
            this.message.warning('上传文件大小限制为：' + fileSize + ' M');
            resultState = false;
          }
        }
      }

      return resultState;
    }
  }
  /**
   * 文件开始上传
   * @param transfer
   */
  public fileUploadStart(transfer: any, data: any) {
    // 上传进度
    data.progress = transfer.percent || 0;
    // 上传开始事件
    if (this.onUploadFileStart) {
      this.onUploadFileStart.emit([transfer, data]);
    }
  }

  /**
   * 文件上传成功
   * @param transfer 文件流模型对象
   */
  public fileUploadSuccess(transfer: any, data: any) {
    this.status.uploadImageData['value'] = transfer.name;
    // 上传进度
    data.progress = transfer.percent || 100;
    // 文件路径
    data.path = transfer.url.replace(/#/ig, '%23');
    // 文件对象
    data.file = transfer.fileInfo;
    // 上传成功事件
    if (this.onUploadFileSuccess) {
      this.onUploadFileSuccess.emit([transfer, data]);
    }
  }

  /**
   * 文件上传失败
   * @param error
   */
  private fileUploadFail(error) {
    if (this.onUploadFileFail) {
      this.onUploadFileFail.emit(error);
    }
  }

  /**
   * 在上传中删除正在上传的文件
   * @param data 当前数据模型
   */
  private removeFile(data) {
    data.value = null;
    data.progress = 0;
    data.path = null;
    if (this.onUploadFileRemove) {
      this.onUploadFileRemove.emit(data);
    }
    this.fileUploader.remove(data.file);
  }

  /**
   * 文件上传获取Token权限
   */
  private fetchFlow() {
    this.oauthService.fetchTokenUsingPasswordFlow(LOGININFO.account, LOGININFO.password);
  }


}
